package com.nulldev.util.data.QueuedArrays;

import java.io.Closeable;
import java.io.IOException;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;

import com.nulldev.util.VariableAPI.ArrayUtils;
import com.nulldev.util.concurrency.threadIt.v4.emapi.ExecutorManager;
import com.nulldev.util.concurrency.threadIt.v4.emapi.ft.FutureTask;
import com.nulldev.util.concurrency.threadIt.v4.emapi.uft.Executable;
import com.nulldev.util.data.Variables;
import com.nulldev.util.data.Arrays.arrays.FastLists;

public class QueuedList<T> implements List<T>, Serializable, Closeable {

	private static final long serialVersionUID = -3826268630482430970L;
	private final BlockingDeque<Executable<?>> tasks = new LinkedBlockingDeque<Executable<?>>();
	private final List<T> core;
	private volatile boolean stop;
	private final FutureTask<?> o = new FutureTask<Object>() {

		@Override
		public Object execute() {
			while (QueuedList.this.core != null || QueuedList.this.stop) {
				try {
					final Executable<?> o = QueuedList.this.tasks.take();
					o.run_st();
				} catch (Exception e) {
				}
			}
			return null;
		}
	};

	public QueuedList(final List<T> list) {
		Variables.notNullE(list);
		this.core = list;
		ExecutorManager.get().queueTask(this.o);
	}

	public static <T> QueuedList<T> make() {
		return new QueuedList<T>(FastLists.list());
	}

	private <E> Executable<E> addTask(final Executable<E> t, final QueuedOperationType op) {
		try {
			if (op == QueuedOperationType.WRITE || op == QueuedOperationType.FINALIZER) {
				tasks.offerFirst(t, 300, TimeUnit.MILLISECONDS);
			} else {
				tasks.offerLast(t, 300, TimeUnit.MILLISECONDS);
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return t;
	}

	@Override
	public int size() {
		return this.addTask(new FutureTask<Integer>() {

			@Override
			public Integer execute() {
				return core.size();
			}

		}, QueuedOperationType.READ).waitTillCompletion();
	}

	@Override
	public boolean isEmpty() {
		return this.addTask(new FutureTask<Boolean>() {

			@Override
			public Boolean execute() {
				return core.isEmpty();
			}

		}, QueuedOperationType.READ).waitTillCompletion();
	}

	@Override
	public boolean contains(final Object o) {
		return this.addTask(new FutureTask<Boolean>() {

			@Override
			public Boolean execute() {
				return core.contains(o);
			}

		}, QueuedOperationType.READ).waitTillCompletion();
	}

	@Override
	public Iterator<T> iterator() {
		return this.addTask(new FutureTask<Iterator<T>>() {

			@Override
			public Iterator<T> execute() {
				return core.iterator();
			}

		}, QueuedOperationType.FINALIZER).waitTillCompletion();
	}

	@Override
	public Object[] toArray() {
		return this.addTask(new FutureTask<Object[]>() {

			@Override
			public Object[] execute() {
				return core.toArray();
			}

		}, QueuedOperationType.FINALIZER).waitTillCompletion();
	}

	@SuppressWarnings("hiding")
	@Override
	public <T> T[] toArray(final T[] a) {
		return this.addTask(new FutureTask<T[]>() {

			@Override
			public T[] execute() {
				return core.toArray(a);
			}

		}, QueuedOperationType.FINALIZER).waitTillCompletion();
	}

	@Override
	public boolean add(final T e) {
		return this.addTask(new FutureTask<Boolean>() {

			@SuppressWarnings("unchecked")
			@Override
			public Boolean execute() {
				return core.add((T) e);
			}

		}, QueuedOperationType.WRITE).waitTillCompletion();
	}

	@Override
	public boolean remove(final Object o) {
		return this.addTask(new FutureTask<Boolean>() {

			@Override
			public Boolean execute() {
				return core.remove(o);
			}

		}, QueuedOperationType.WRITE).waitTillCompletion();
	}

	@Override
	public boolean containsAll(final Collection<?> c) {
		return this.addTask(new FutureTask<Boolean>() {

			@Override
			public Boolean execute() {
				return core.containsAll(c);
			}

		}, QueuedOperationType.READ).waitTillCompletion();
	}

	@Override
	public boolean addAll(final Collection<? extends T> c) {
		return this.addTask(new FutureTask<Boolean>() {

			@Override
			public Boolean execute() {
				return core.addAll(c);
			}

		}, QueuedOperationType.WRITE).waitTillCompletion();
	}

	@Override
	public boolean addAll(final int index, final Collection<? extends T> c) {
		return this.addTask(new FutureTask<Boolean>() {

			@Override
			public Boolean execute() {
				return core.addAll(index, c);
			}

		}, QueuedOperationType.WRITE).waitTillCompletion();
	}

	@Override
	public boolean removeAll(final Collection<?> c) {
		return this.addTask(new FutureTask<Boolean>() {

			@Override
			public Boolean execute() {
				return core.removeAll(c);
			}

		}, QueuedOperationType.WRITE).waitTillCompletion();
	}

	@Override
	public boolean retainAll(final Collection<?> c) {
		return this.addTask(new FutureTask<Boolean>() {

			@Override
			public Boolean execute() {
				return core.retainAll(c);
			}

		}, QueuedOperationType.WRITE).waitTillCompletion();
	}

	@Override
	public void clear() {
		this.addTask(new FutureTask<Object>() {

			@Override
			public Object execute() {
				core.clear();
				return null;
			}

		}, QueuedOperationType.FINALIZER).waitTillCompletion();
	}

	@Override
	public T get(final int index) {
		return this.addTask(new FutureTask<T>() {

			@Override
			public T execute() {
				return core.get(index);
			}

		}, QueuedOperationType.READ).waitTillCompletion();
	}

	@Override
	public T set(final int index, final T element) {
		return this.addTask(new FutureTask<T>() {

			@Override
			public T execute() {
				return core.set(index, element);
			}

		}, QueuedOperationType.WRITE).waitTillCompletion();
	}

	@Override
	public void add(final int index, final T element) {
		this.addTask(new FutureTask<Object>() {

			@Override
			public Object execute() {
				core.add(index, element);
				return null;
			}

		}, QueuedOperationType.WRITE).waitTillCompletion();
	}

	@Override
	public T remove(final int index) {
		return this.addTask(new FutureTask<T>() {

			@Override
			public T execute() {
				return core.remove(index);
			}

		}, QueuedOperationType.WRITE).waitTillCompletion();
	}

	@Override
	public int indexOf(final Object o) {
		return this.addTask(new FutureTask<Integer>() {

			@Override
			public Integer execute() {
				return core.indexOf(o);
			}

		}, QueuedOperationType.READ).waitTillCompletion();
	}

	@Override
	public int lastIndexOf(final Object o) {
		return this.addTask(new FutureTask<Integer>() {

			@Override
			public Integer execute() {
				return core.lastIndexOf(o);
			}

		}, QueuedOperationType.READ).waitTillCompletion();
	}

	@Override
	public ListIterator<T> listIterator() {
		return this.addTask(new FutureTask<ListIterator<T>>() {

			@Override
			public ListIterator<T> execute() {
				return core.listIterator();
			}

		}, QueuedOperationType.FINALIZER).waitTillCompletion();
	}

	@Override
	public ListIterator<T> listIterator(final int index) {
		return this.addTask(new FutureTask<ListIterator<T>>() {

			@Override
			public ListIterator<T> execute() {
				return core.listIterator(index);
			}

		}, QueuedOperationType.FINALIZER).waitTillCompletion();
	}

	@Override
	public List<T> subList(final int fromIndex, final int toIndex) {
		return this.addTask(new FutureTask<List<T>>() {

			@Override
			public List<T> execute() {
				return core.subList(fromIndex, toIndex);
			}

		}, QueuedOperationType.FINALIZER).waitTillCompletion();
	}

	public static void main(String[] args) {
		final QueuedList<String> s = make();
		s.add("Hello!");
		s.add("World!");
		ArrayUtils.printLln(s);
	}

	@Override
	public void close() throws IOException {
		this.core.clear();
		this.stop = true;
	}

	/* NCOMPAT: finalize() was removed as JRE 18 removes finalization. */

}
